/**
 * 
 */
package com.geekteam.masterenglish.service;

import java.io.File;
import java.io.IOException;

import android.app.Service;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.audiofx.Equalizer;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;

import com.geekteam.masterenglish.utils.Constants.BundleKey;
import com.geekteam.masterenglish.utils.StorageUtil;
import com.geekteam.masterenglish.utils.Utils;

/**
 * @author MTROL
 * 
 */
public class MediaPlaybackService extends Service implements
		MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener,
		MediaPlayer.OnErrorListener, MediaPlayer.OnBufferingUpdateListener {

	private static final String TAG = "MediaPlaybackService";
	private final Binder mBinder = new LocalBinder();
	private String mUrl;
	private MediaPlayer mMediaPlayer;
	private Equalizer mEqualizer;
	private State mState;
	private OnMusicLisener mMusicLisener;
	
	@Override
	public IBinder onBind(Intent intent) {
		return mBinder;
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Bundle bundle = intent.getBundleExtra(BundleKey.MAIN_KEY);
		mUrl = bundle.getString(BundleKey.URL);
		initMediaPlayer();
		initEqualizer();
		playMusic();

		return START_STICKY;
	}

	private void playMusic() {
		try {
			if (mMediaPlayer != null) {
				mState = State.Retrieving;
				mMediaPlayer.reset();
				sendState();
			}
			if (mUrl != null && !mUrl.equalsIgnoreCase("")) {
				Uri path = null;
				if(mUrl.startsWith("/")){
					path = Uri.fromFile(new File(mUrl));
				}else{
					path = Uri.parse(mUrl);
				}
				 
				try {
					mMediaPlayer.setDataSource(getApplicationContext(), path);
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalStateException e) {
					mMediaPlayer.reset();
					try {
						mMediaPlayer.setDataSource(getApplicationContext(), path);
					} catch (IOException e1) {
						e1.printStackTrace();
					}
					e.printStackTrace();
				} catch (Exception e) {
					e.printStackTrace();
				}

				mState = State.Preparing;
				mMediaPlayer.prepareAsync();
				
				sendState();
			}
		} catch (Exception ex) {
			mState = State.Retrieving;
			if (mMediaPlayer != null)
				mMediaPlayer.reset();
			ex.printStackTrace();
		}
	}

	private void initMediaPlayer() {
		if (mMediaPlayer == null) {
			mMediaPlayer = new MediaPlayer();
			mMediaPlayer.setOnPreparedListener(this);
			mMediaPlayer.setOnErrorListener(this);
			mMediaPlayer.setOnCompletionListener(this);
			mMediaPlayer.setOnBufferingUpdateListener(this);
			mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
		}
	}

	private void initEqualizer() {
		if (Utils.hasGingerbread() && mEqualizer == null) {
			mEqualizer = new Equalizer(0, mMediaPlayer.getAudioSessionId());
			mEqualizer.setEnabled(true);
			// read from file to get preset
			int valueEqualizer = StorageUtil
					.readConfig(getApplicationContext());
			try{
				if(valueEqualizer>=0 && valueEqualizer < mEqualizer.getNumberOfPresets()){
					mEqualizer.usePreset((short) valueEqualizer);
				}
			}catch(IllegalArgumentException ex){
				ex.printStackTrace();
			}
		}
	}

	@Override
	public void onBufferingUpdate(MediaPlayer media, int percent) {
		if(mMusicLisener!=null){
			mMusicLisener.onBufferingUpdate(percent);
		}
	}

	@Override
	public boolean onError(MediaPlayer media, int what, int extra) {
		switch (what) {
		case MediaPlayer.MEDIA_ERROR_UNKNOWN:
			Log.e(TAG, "unknown media playback error");
			break;
		case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
			Log.e(TAG, "server connection died");
		default:
			Log.e(TAG, "generic audio playback error");
			break;
		}

		switch (extra) {
		case MediaPlayer.MEDIA_ERROR_IO:
			Log.e(TAG, "IO media error");
			break;
		case MediaPlayer.MEDIA_ERROR_MALFORMED:
			Log.e(TAG, "media error, malformed");
			break;
		case MediaPlayer.MEDIA_ERROR_UNSUPPORTED:
			Log.e(TAG, "unsupported media content");
			break;
		case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
			Log.e(TAG, "media timeout error");
			break;
		default:
			Log.e(TAG, "unknown playback error");
			break;
		}

		mState = State.Retrieving;
		sendState();
		return true;
	}

	@Override
	public void onCompletion(MediaPlayer media) {
//		mState = State.Playing;
//		mMediaPlayer.start();
	}

	@Override
	public void onPrepared(MediaPlayer media) {
		mState = State.Prepared;
		start();
	}

	@Override
	public void onDestroy() {
		if (mMediaPlayer != null) {
			mMediaPlayer.release();
		}
		if(mMusicLisener!=null){
			mMusicLisener = null;
		}
		mState = State.Retrieving;
	}
	
	public void seekTo(int pos){
		if (mState.equals(State.Playing) || mState.equals(State.Paused)) {
			try {
				mMediaPlayer.seekTo(pos);
			} catch (IllegalStateException e) {
				e.printStackTrace();
			}
		}
	}
	
	public void pause(){
		if(mState.equals(State.Playing)){
			mMediaPlayer.pause();
			mState = State.Paused;
			//TODO notify to ui and os bar
		}
	}
	
	public void start(){
		if(mState.equals(State.Prepared) || mState.equals(State.Paused)){
			try {
				//TODO setting looping by user here
				mMediaPlayer.setLooping(true);
				mMediaPlayer.start();
				mState = State.Playing;
				//TODO notiy to ui and os bar
				sendState();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	public void startLession(String url, String title){
		mUrl = url;
		initMediaPlayer();
		initEqualizer();
		playMusic();
	}
	
	public int getCurrentPosition() {
		if (!mState.equals(State.Preparing) && !mState.equals(State.Retrieving)) {
			return mMediaPlayer.getCurrentPosition();
		}
		return 0;
	}
	
	public int getDuration() {
		if (!mState.equals(State.Preparing) && !mState.equals(State.Retrieving)) {
			return mMediaPlayer.getDuration();
		}
		return 0;
	}
	
	public boolean isPlaying(){
		if(mState==null){
			mState = State.Retrieving;
			return false;
		}
		if(mState.equals(State.Playing)){
			return true;
		}else{
			return false;
		}
	}
	
	public void setOnMusicLisener(OnMusicLisener mMusicLisener) {
		this.mMusicLisener = mMusicLisener;
	}

	private void sendState(){
		if(mMusicLisener!=null){
			mMusicLisener.onStateChange(mState);
		}
	}
	
	public enum State {
		Retrieving, Stopped, Preparing, Prepared, Playing, Paused
	};

	public class LocalBinder extends Binder {
		public MediaPlaybackService getService() {
			return MediaPlaybackService.this;
		}
	}
	
	public interface OnMusicLisener{
		public void onBufferingUpdate(int percent);
		public void onError(int code, String message);
		public void onStateChange(State state);
	}
}
